use core::{cell::UnsafeCell, ptr::null_mut};

use crate::{
    c::rtx_os::{
        osEventFlagsAttr_t, osEventFlagsClear, osEventFlagsId_t, osEventFlagsNew, osEventFlagsSet,
        osEventFlagsWait, osFlagsWaitAll, osFlagsWaitAny, osRtxEventFlags_t,
    },
    utils::AlignStore,
};

const CB_SIZE: usize = size_of::<osRtxEventFlags_t>();

unsafe impl Send for EventFlags {}
unsafe impl Sync for EventFlags {}

pub struct EventFlags {
    cb_mem: AlignStore<CB_SIZE>,
    id: UnsafeCell<osEventFlagsId_t>,
}

impl EventFlags {

    pub const fn const_new() -> Self {
        Self {
            cb_mem: AlignStore::const_new(),
            id: UnsafeCell::new(null_mut())
        }
    }

    pub unsafe fn create(&self, name: &str) {
        let attr = osEventFlagsAttr_t {
            name: name.as_ptr() as *const i8,
            attr_bits: 0,
            cb_mem: self.cb_mem.raw_ptr(),
            cb_size: CB_SIZE as u32,
        };
        let id = osEventFlagsNew(&attr);
        #[cfg(feature = "assert")]
        assert!(id != null_mut(), "event falgs create fail");
        *self.id.get() = id;
    }

    pub unsafe fn set_flags(&self, flags: u32) -> u32 {
        osEventFlagsSet(*self.id.get(), flags)
    }

    pub unsafe fn clear_flags(&self, flags: u32) -> u32 {
        osEventFlagsClear(*self.id.get(), flags)
    }

    pub unsafe fn wait_any_flags(&self, flags: u32, timeout: u32) -> u32 {
        osEventFlagsWait(*self.id.get(), flags, osFlagsWaitAny, timeout)
    }

    pub unsafe fn wait_all_flags(&self, flags: u32, timeout: u32) -> u32 {
        osEventFlagsWait(*self.id.get(), flags, osFlagsWaitAll, timeout)
    }
}
